/**
 * 
 */
package com.module.bp.ui;

import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.Iterator;

import com.dalonedrau.jogl.engine.GameApplet;
import com.dalonedrau.jogl.engine.GameDrawable;
import com.dalonedrau.jogl.engine.Render;
import com.dalonedrau.jogl.opengl.sprite.BasicSpriteObject;
import com.dalonedrau.jogl.opengl.sprite.SpriteBase;
import com.dalonedrau.jogl.opengl.sprite.SpriteImageObject;
import com.dalonedrau.jogl.opengl.sprite.SpriteImageObjectFactory;
import com.dalonedrau.jogl.opengl.ui.Label;
import com.dalonedrau.jogl.opengl.ui.UIFactory;
import com.dalonedrau.jogl.opengl.ui.border.VXBorderNoEdge;
import com.dalonedrau.jogl.opengl.ui.panel.LandscapePagePanel;
import com.dalonedrau.jogl.opengl.ui.panel.Panel;
import com.dalonedrau.vectors.Vector3;
import com.module.bp.bus.BPHexMap;
import com.module.bp.engine.BPController;
import com.module.bp.engine.Turn;
import com.module.bp.player.BPConsts;
import com.module.bp.player.BPParty;
import com.module.bp.view.OverworldView;

/**
 * @author Donald
 */
public final class ActionMenu extends LandscapePagePanel {
	private static final int myHeight = 32;
	private static final int spacing1 = 2;
	private static final int spacing2 = 4;
	/** the singleton instance of {@link ActionMenu}. */
	private static ActionMenu	instance;
	/**
	 * Gets the singleton instance of {@link ActionMenu}.
	 * @return {@link ActionMenu}
	 */
	public static ActionMenu getInstance() {
		if (ActionMenu.instance == null) {
			ActionMenu.instance = new ActionMenu();
		}
		return ActionMenu.instance;
	}
	/** the action helper. */
	private Label			actionHelper;
	/** the list of button sprites. */
	private SpriteBase[]	sprites;
	/**
	 * Creates a new instance of {@link ActionMenu}.
	 */
	private ActionMenu() {
		super(Panel.LANDSCAPE_CENTER);
		// initialize sprites
		try {
			sprites = new SpriteBase[7];
			String[] list = new String[] {
					"btn_action_rest", "btn_action_travel", "btn_action_cache",
					"btn_action_town", "btn_action_temple",
					"btn_action_castle",
					"btn_action_cancel"
			};
			for (int i = 0; i < sprites.length; i++) {
				SpriteBase sb = new BasicSpriteObject();
				SpriteImageObject img =
						SpriteImageObjectFactory.getInstance().getImageByName(
								list[i]);
				sb.setImageRefId(img.getRefId());
				sb.setWidth(img.getWidth());
				sb.setHeight(img.getHeight());
				sb.setPosition(new Vector3(-1, 0, 0));
				sprites[i] = sb;
			}
			actionHelper = UIFactory.getInstance().getStandardH2Label(
					"Travel To A New Spot");
			actionHelper.setBorder(new VXBorderNoEdge());
			actionHelper.setText("");
		} catch (Exception ex) {
			JOGLErrorHandler.getInstance().fatalError(ex);
		}
	}
	private int menuWidth;
	/**
	 * Displays possible actions, either above or below the party sprite.
	 * @param parentx the x-coordinate of the party sprite
	 * @param parenty the y-coordinate of the party sprite
	 * @param cx the container's x-coordinate
	 * @param cy the container's y-coordinate
	 * @param cw the container's width
	 * @param ch the container's height
	 */
	public void displayActions(final double parentx, final double parenty,
			final double cx, final double cy, final int cw, final int ch) {
		containerX = cx;
		containerY = cy;
		containerWidth = cw;
		containerheight = ch;
		if (super.getPosition() != null) {
			// which phase is this?
			if (Turn.getInstance().getCurrentPhase() == Turn.PHASE_ACTION) {
				// how many actions can be shown?
				int actions = 4;
				if (BPParty.getInstance().isInCastleHex()
						|| BPParty.getInstance().isInRuinsHex()
						|| BPParty.getInstance().isInTempleHex()
						|| BPParty.getInstance().isInTownHex()) {
					actions = 5;
				}
				// position the menu
				double myx = 0, myy = 0;
				super.setPreferredSize(actions * 32, 32);
				// preference is to position menu below party sprite
				int totalHeight = myHeight + spacing1 + spacing2 * 2;
				totalHeight += actionHelper.getPreferredSize().height;
				if (parenty - totalHeight < cy) { 
					// no room below party sprite, position above
					myy = parenty + spacing1 + myHeight;
					positionAbove = true;
				} else { 
					// position below party sprite
					myy = parenty - spacing1 - myHeight;
					positionAbove = false;
				}
				// try to center menu horizontally with party sprite
				menuWidth = actions * myHeight;
				myx = parentx + 16 - menuWidth / 2;
				if (myx < cx + spacing2) {
					myx = cx + spacing2;
				} else if (myx + menuWidth > cx + cw - spacing2) {
					myx = (cx + cw) - menuWidth - spacing2;
				}
				super.setPosition(myx, myy, super.getPosition().getZ());

				// position actions
				for (int i = 0; i < sprites.length; i++) {
					sprites[i].setPosition(new Vector3(-1, 0, 0));
				}
				// rest
				sprites[0].setPosition(myx, myy, super.getPosition().getZ());
				myx += 32;
				// travel
				sprites[1].setPosition(myx, myy, super.getPosition().getZ());
				myx += 32;
				// cache
				sprites[2].setPosition(myx, myy, super.getPosition().getZ());
				myx += 32;
				// town
				if (BPParty.getInstance().isInTownHex()) {
					sprites[3].setPosition(
							myx, myy, super.getPosition().getZ());
					myx += 32;
				}
				// temple
				if (BPParty.getInstance().isInTempleHex()) {
					sprites[4].setPosition(
							myx, myy, super.getPosition().getZ());
					myx += 32;
				}
				// castle
				if (BPParty.getInstance().isInCastleHex()) {
					sprites[5].setPosition(
							myx, myy, super.getPosition().getZ());
					myx += 32;
				}
				// ruins
				if (BPParty.getInstance().isInRuinsHex()) {
					// sprites[6].setPosition(myx, myy,
					// super.getPosition().getZ());
					myx += 32;
				}
				// cancel
				sprites[6].setPosition(myx, myy, super.getPosition().getZ());
			} else {

			}
		}
	}
	private boolean debug = false;
	/** Handles the action when the user clicks the 'Travel' button. */
	private void handleMCTravel() {
		// get allowed travel locations
		// get party's vertex location
		int vertex = 
			BPHexMap.getInstance().getHexVertex(
					BPParty.getInstance().getCurrentHex());
		// find all travelling adjacencies
		int movesLeft = BPParty.getInstance().getNumMovesPossible();
		movesLeft -= BPParty.getInstance().getNumMovesTaken();
		ArrayList<Integer> list = new ArrayList<Integer>();
		Iterator<Integer> iter = 
			BPController.getInstance().getOverworldGraph()
		.getWalkingAdjacencies(vertex, movesLeft).iterator();
		// set highlights for possible move points
		if (debug) {
			System.out.println("walking path from "
					+ BPParty.getInstance().getCurrentHex());
			System.out.println(vertex);
		}
		while (iter.hasNext()) {
			int n = iter.next();
			if (debug) {
				System.out.println(n);
				System.out.println(
						BPHexMap.getInstance().getHexVector(n));
			}
			if (n < 460) {
				list.add(n);
			}
		}
		// ASSIGN POSSIBLE TRAVEL HEXES
		OverworldView.getInstance().setMoveRadius(
				list.toArray(new Integer[list.size()]));
		// find all travelling adjacencies
		list.clear();
		iter = 
			BPController.getInstance().getOverworldGraph()
		.getWalkingAdjacencies(vertex, 1).iterator();
		// set highlights for possible move points

		if (debug) {
			System.out.println("walking path from "
					+ BPParty.getInstance().getCurrentHex());
			System.out.println(vertex);
		}
		while (iter.hasNext()) {
			int n = iter.next();
			if (debug) {
				System.out.println(n);
				System.out.println(
						BPHexMap.getInstance().getHexVector(n));
			}
			if (n < 460) {
				list.add(n);
			}
		}
		// ASSIGN POSSIBLE TRAVEL HEXES
		OverworldView.getInstance().setPossibleTravelMoves(
				list.toArray(new Integer[list.size()]));
		// SET MAP TO MOVE SELECTION
		OverworldView.getInstance().setMapMode(
				BPConsts.OVM_MOVE_SELECTION_MODE);
	}
	/**
	 * {@inheritDoc}
	 */
	@Override
	public void handleMouseClick(final MouseEvent e, final float x, 
			final float y) {
		if (super.contains(x, y)) {
			// get rid of action menu
			OverworldView.getInstance().removeFlag(
					OverworldView.OWV_SHOW_ACTION_MENU);
			GameDrawable.setCursor(Cursor.DEFAULT_CURSOR);
			actionHelper.setText("");
			// figure out next action
			if (Turn.getInstance().getCurrentPhase() == Turn.PHASE_ACTION) {
				double inX = x - super.getPosition().getX();
				int index = (int) inX / 32;
				if (debug) {
					System.out.println("click over index " + index);
				}
				switch (index) {
				case 0: // REST
					break;
				case 1: // TRAVEL
					handleMCTravel();
					break;
				case 2: // CACHE
					break;
				case 3:
					if (BPParty.getInstance().isInCastleHex()) {} else if (BPParty
							.getInstance().isInRuinsHex()) {} else if (BPParty
							.getInstance().isInTempleHex()) {} else if (BPParty
							.getInstance().isInTownHex()) {} else { // CANCEL
						// allow the action menu again
						OverworldView.getInstance().assignFlag(
								OverworldView.OWV_ALLOW_ACTION_MENU);
						OverworldView.getInstance().setMapMode(
								BPConsts.OVM_FREE_MODE);
					}
					break;
				case 4: // CANCEL
					// allow the action menu again
					OverworldView.getInstance().assignFlag(
							OverworldView.OWV_ALLOW_ACTION_MENU);
					OverworldView.getInstance().removeFlag(
							OverworldView.OWV_SHOW_ACTION_MENU);
					// set to free mode
					OverworldView.getInstance().setMapMode(
							BPConsts.OVM_FREE_MODE);
					break;
				}
			}
		} else {
			GameDrawable.setCursor(Cursor.DEFAULT_CURSOR);
			actionHelper.setText("");
		}
	}
	/**
	 * {@inheritDoc}
	 */
	@Override
	public void handleMouseOver(float x, float y) {
		if (super.contains(x, y)) {
			GameDrawable.setCursor(Cursor.HAND_CURSOR);
			// figure out tooltip
			if (Turn.getInstance().getCurrentPhase() == Turn.PHASE_ACTION) {
				double inX = x - super.getPosition().getX();
				int index = (int) inX / 32;
				if (debug) {
				System.out.println("over index " + index);
				}
				switch (index) {
				case 0:
					actionHelper.setText("Rest For A Day");
					break;
				case 1:
					actionHelper.setText("Travel To A New Spot");
					break;
				case 2:
					actionHelper.setText("Hide A Cache Of Gold");
					break;
				case 3:
					if (BPParty.getInstance().isInCastleHex()) {
						actionHelper.setText("Enter Castle");
					} else if (BPParty.getInstance().isInRuinsHex()) {
						actionHelper.setText("Enter Ruins");
					} else if (BPParty.getInstance().isInTempleHex()) {
						actionHelper.setText("Enter Temple");
					} else if (BPParty.getInstance().isInTownHex()) {
						actionHelper.setText("Enter Town");
					} else {
						actionHelper.setText("Cancel");
					}
					break;
				case 4:
					actionHelper.setText("Cancel");
					break;
				}
				// position actionHelper
				double menux = sprites[0].getPosition().getX();
				double menuy = sprites[0].getPosition().getY();
				double hy = menuy - spacing2;
				hy -= actionHelper.getPreferredSize().height;
				if (positionAbove) {
					hy = menuy + this.myHeight + spacing2;
				}
				// try to center label in relation to action menu
				double hx = menux + menuWidth / 2;
				hx -= actionHelper.getPreferredSize().width / 2;
				if (hx < containerX + spacing2) {
					// if helper label is over container's left edge, or 
					// less than 4px from container's left edge
					hx = containerX + spacing2;
				} else if (hx + actionHelper.getPreferredSize().width 
						> containerX + containerWidth - spacing2) {
					// if helper label is over container's right edge, or 
					// less than 4px from container's right edge
					hx = containerX + containerWidth - spacing2;
					hx -= actionHelper.getPreferredSize().width;
				}
				actionHelper.setPosition(hx, hy, super.getPosition().getZ());
			}
		} else {
			GameDrawable.setCursor(Cursor.DEFAULT_CURSOR);
			actionHelper.setText("");
		}
	}
	private boolean positionAbove;
	private double containerX;
	private double containerY;
	private double containerWidth;
	private double containerheight;
	/**
	 * {@inheritDoc}
	 */
	@Override
	public void prepareForRendering() throws Exception {
		for (int i = 0; i < sprites.length; i++) {
			if (sprites[i].getPosition().getX() > -1) {
				Render.getInstance().registerEntity(sprites[i]);
			}
		}
		if (!actionHelper.getText().equalsIgnoreCase("")) {
			actionHelper.prepareForRendering();
		}
	}
}
